package se.webbzon.boltzmann.world;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import se.webbzon.boltzmann.battle.environment.BattleEnvironment;
import se.webbzon.boltzmann.battle.group.BattleGroup;
import se.webbzon.boltzmann.battle.npc.DefendingDuty;
import se.webbzon.boltzmann.battle.object.npc.BattleNPC;
import se.webbzon.boltzmann.battle.object.spawner.BattleSpawner;
import se.webbzon.boltzmann.battle.round.BattleRound;
import se.webbzon.boltzmann.battle.round.BattleRoundListener;
import se.webbzon.boltzmann.game.character.CharacterFacing;
import se.webbzon.boltzmann.game.object.camera.GameCamera;
import se.webbzon.boltzmann.hud.TopBar;
import se.webbzon.boltzmann.object.background.Background;
import se.webbzon.boltzmann.object.escaper.DefaultEscaper;
import se.webbzon.boltzmann.player.Player;
import se.webbzon.oschi01.worldarea.WorldArea;

public class BattleWorldLoader extends AbstractWorldLoader {
	
	// The player associated with this battle loader
	private final Player player;
	
	// A list containing all the participating battle groups 
	private final List<BattleGroup> battleGroups;
	
	// A collection of all the battle round listeners 
	// associated with this battle world loader
	private final Collection<BattleRoundListener> listeners;

	/*============================================================
	Constructors
	============================================================*/
	
	public BattleWorldLoader(	BattleEnvironment env,
								String worldAreaName,
								Player player,
								List<BattleGroup> battleGroups) {
		this(	env,worldAreaName,player,battleGroups,
				new ArrayList<BattleRoundListener>());
	}
	
	public BattleWorldLoader(	BattleEnvironment env,
								String worldAreaName,
								Player player,
								List<BattleGroup> battleGroups,
								Collection<BattleRoundListener> listeners) {
		super(env, worldAreaName);
		this.player = player;
		this.battleGroups = battleGroups;
		this.listeners = listeners;
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	@Override public WorldArea load() throws WorldLoaderException {
		WorldArea world = super.load();
		
		// Add an escaper to the world
		world.createInstance(new DefaultEscaper());
		
		Collection<BattleSpawner> spawners = world.findInstances(BattleSpawner.class);
		BattleEnvironment benv = (BattleEnvironment) getEnvironment();
		
		// Match the participant to the spawner
		for (BattleGroup group : battleGroups)
			for (BattleNPC npc : group.getParticipants()) {
				BattleSpawner s = null;
				int order = Integer.MAX_VALUE;
				
				// Find the matching spawner with the lowest order number
				for (BattleSpawner spawner : spawners)
					if (spawner.getFactionId() == group.getFactionId() &&
						spawner.getGroupId() == group.getGroupId() &&
						spawner.getOrder() <= order) {
						s = spawner;
						order = spawner.getOrder();
					}
				
				// Spawn the non-player character
				if (s != null) {
					npc.setPosition(s.getX(), s.getY(), s.getZ());
					npc.setSize(s.getWidth(), s.getHeight(), s.getDepth());
					final CharacterFacing facing = 
							s.isFacingLeft() ? 	CharacterFacing.LEFT_DOWN : 
												CharacterFacing.RIGHT_DOWN;
					npc.assignDuty(new DefendingDuty(npc,facing));
					world.createInstance(npc);
					spawners.remove(s);
				} else 
					throw new WorldLoaderException(	"Missing battle spawner, " +
													"faction id: " + 
													group.getFactionId() +
													", group id: " + 
													group.getGroupId());
			}
		
		
		world.createInstance(new Background(benv));
		
		// Add a top bar
		TopBar topBar = new TopBar(player, benv.getLayout().getTopBarLayout());
		world.createInstance(topBar);
		topBar.setForceShow(true);
		
		// Add a camera
		GameCamera camera = new GameCamera(player);
		camera.addView(player.getView());
		world.createInstance(camera);
		
		// Start the battle round
		BattleRound battleRound = new BattleRound(world,battleGroups);
		battleRound.addListener(new BattleRoundListenerImpl(camera));
		
		// Add all the listeners to the battle round
		for (BattleRoundListener listener : listeners)
			battleRound.addListener(listener);
			
		battleRound.start();
		
		return world;
	}
	
	/*============================================================
	Private Classes
	============================================================*/
	
	private final class BattleRoundListenerImpl implements BattleRoundListener {
		
		// The game camera associated with this battle round listener
		private GameCamera camera;
		
		/*============================================================
		Constructors
		============================================================*/
		
		public BattleRoundListenerImpl(GameCamera camera) {
			this.camera = camera;
		}
		
		/*============================================================
		Public Methods
		============================================================*/

		@Override public void roundStart(BattleRound battleRound) {};
		
		@Override public void roundComplete(BattleRound battleRound) {};

		@Override public void groupStart(BattleRound battleRound, BattleGroup group) {};
		
		@Override public void groupComplete(BattleRound battleRound, BattleGroup group) {};

		@Override public void turnStart(BattleRound battleRound, BattleNPC participant) {
			camera.setTarget(battleRound.getCurrentParticipant());
		}
		
		@Override public void turnComplete(BattleRound battleRound, BattleNPC participant) {};

		@Override public void battleStart(BattleRound battleRound, WorldArea world) {};
		
		@Override public void battleComplete(BattleRound battleRound, int factionId) {};	
		
	}

}
